<?php

class PagesResource extends Resource
{
    const ID = "pages/pages";

    /**
     * @var PageInfo[]
     */
    private $pages = array();
    /**
     * @var string
     */
    private $defaultPageClass = "Page";
    /**
     * @var Substitutions
     */
    private $substitutions;
    private $siteLanguage;

    public function __construct( ResourceManager $resourceManager, Substitutions $substitutions )
    {
        parent::__construct( $resourceManager );
        $this->substitutions = $substitutions;
        $this->siteLanguage = Core::GetLanguage();
    }

    public function GetId()
    {
        return self::ID;
    }

    public function GetFreshData()
    {
        $this->LoadPages();

        $isMultiLanguageSite = $this->siteLanguage != SiteLanguage::EN;
        if ( $isMultiLanguageSite )
        {
            $this->LoadLngPages();
            $this->LoadLngQuickLinks();
        }
        else
        {
            $this->LoadQuickLinks();
        }
        $this->LoadPageTree();

        foreach ( $this->pages as &$pageInfo )
        {
            list($pageInfo->path, $pageInfo->name, $pageInfo->title, $pageInfo->keywords, $pageInfo->description) =
                $this->substitutions->Process( array(
                    $pageInfo->path, $pageInfo->name, $pageInfo->title, $pageInfo->keywords, $pageInfo->description
                )
            );
        }

        return $this->pages;
    }

    /**
     * Sets default class for Pages.
     * @param string $pageClass
     */
    public function SetDefaultPageClass( $pageClass )
    {
        $this->defaultPageClass = $pageClass;
    }

    private function LoadPages()
    {
        $xml = @file_get_contents(PAGES_FILE);
        $doc = Util::CreateXmlDocument($xml, TRUE);

        if ($doc)
        {
            $xpath = new XPathHelper($doc);
            $nodes = $xpath->GetNodes("/pages/page");
            foreach ($nodes as $node)
            {
                $page = $this->LoadPageData($node, $xpath);
                $this->pages[$page->id] = $page;
            }

            $this->LoadPagesRefererAndUpdateDefaultClass();
        }
    }

    /**
     * Loads pages infos for additional site languages.
     */
    private function LoadLngPages()
    {
        $basePages = $this->pages;

        $lngPagesFilePath = $this->GetLangPagesFilePath();
        if (!file_exists($lngPagesFilePath))
        {
            return;
        }

        $xml = @file_get_contents($lngPagesFilePath);
        $doc = Util::CreateXmlDocument($xml, TRUE);

        $xpath = new XPathHelper($doc);
        $nodes = $xpath->GetNodes("/pages/page");

        foreach ($nodes as $node)
        {
            $this->LoadLngPageFromNode($node, $xpath, $basePages);
        }

        $this->LoadPagesRefererAndUpdateDefaultClass();
    }

    /**
     * @param DOMNode $node
     * @param XPathHelper $xpath
     * @param array $basePages of EN site
     */
    private function LoadLngPageFromNode(DOMNode $node, XPathHelper $xpath, array $basePages)
    {
        $lngPage = $this->LoadPageData($node, $xpath);
        $lngPage->language = $this->siteLanguage;

        $pageExistsOnNationalSite = isset($basePages[$lngPage->id]);
        if ($pageExistsOnNationalSite)
        {
            $basePage = $basePages[$lngPage->id];
            $lngPage->Init($basePage);
            $lngPage->SetPageTreesSettings($basePage);
        }

        $refPageIsNotDefinedInMultilangPagesConfig = $lngPage->ref && !isset($this->pages[$lngPage->ref]) && isset($basePages[$lngPage->ref]);
        if ($refPageIsNotDefinedInMultilangPagesConfig)
        {
            $this->pages[$lngPage->ref] = $basePages[$lngPage->ref];
        }

        if (empty($lngPage->params) && isset($basePages[$lngPage->id]))
        {
            $lngPage->params = $basePages[$lngPage->id]->params;
        }

        $this->pages[$lngPage->id] = $lngPage;
    }

    private function GetLangPagesFilePath()
    {
        return str_replace('%LNG%', $this->siteLanguage, LNG_PAGES_FILE_PATTERN);
    }

    private function LoadPagesRefererAndUpdateDefaultClass()
    {
        foreach ($this->pages as $page)
        {
            if ($page->ref)
            {
                $this->LoadRefererPageData($page);
            }
        }

        $this->AddDefaultClassToPages();
    }

    private function AddDefaultClassToPages()
    {
        foreach ($this->pages as &$page)
        {
            Util::SetIfNull($page->class, $this->defaultPageClass);
        }
        unset($page);
    }

    /**
     *
     * @param $node
     * @param $xpath
     * @return PageInfo
     */
    private function LoadPageData( $node, $xpath )
    {
        $id = $node->getAttribute("id");
        $language = $node->getAttribute("language");

        $page = new PageInfo();

        $this->ReadAttribute($page, $node, "search");
        $this->ReadAttribute($page, $node, "comments");
        $this->ReadAttribute($page, $node, "static");

        $ref = $node->getAttribute("ref");
        if ($ref)
        {
            $page->ref = $ref;
        }

        $this->ReadAttribute($page, $node, "use_nginx_cache", "useNginxCache");

        $page->id           = $id;
        $page->language     = (!empty($language)) ? $language : SiteLanguage::EN;
        $page->path         = $xpath->GetText("path",         $node);
        $page->tplFile      = $xpath->GetText("tpl_file",     $node);
        $page->phpFile      = $xpath->GetText("php_file",     $node);
        $page->class        = $xpath->GetText("class",        $node);
        $page->title        = $xpath->GetText("title",        $node);
        $page->icon         = $xpath->GetText("icon",         $node);
        $page->name         = $xpath->GetText("name",         $node);
        $page->keywords     = $xpath->GetText("keywords",     $node);
        $page->description  = $xpath->GetText("description",  $node);
        $page->seoBlock     = $xpath->GetText("seo_block",    $node);
        $page->name         = $xpath->GetText("name",         $node);
        $page->loginUrl     = $xpath->GetText("login_url",    $node);
        $page->canonical    = $xpath->GetText("canonical",    $node);

        $viewNode = $xpath->GetNode( "view", $node );
        if ( !empty( $viewNode ) )
        {
            $this->ReadAttribute($page, $viewNode, "top");
            $this->ReadAttribute($page, $viewNode, "left");
            $this->ReadAttribute($page, $viewNode, "right");
            $this->ReadAttribute($page, $viewNode, "bottom");
            $this->ReadAttribute($page, $viewNode, "topMenuExpand");
            $this->ReadAttribute($page, $viewNode, "featured_customers");
            $page->themeID = ( $viewNode->hasAttribute( "theme_id" ) ) ? $viewNode->getAttribute( "theme_id" ) : $page->themeID;
        }

        $page->javascripts  = Util::ToArrayValue($xpath->GetText("javascripts",  $node));
        $page->stylesheets  = Util::ToArrayValue($xpath->GetText("stylesheets",  $node));

        $this->ReadAttribute($page, $node, "secure");
        $sslRequired = $node->getAttribute("ssl_required");
        if ($sslRequired)
        {
            $page->sslRequired = ( $sslRequired === 'true' || $sslRequired === 'false' )
                ? ($sslRequired === 'true')
                : $sslRequired;
        }

        $paramNodes = $xpath->GetNodes("params/param", $node);
        foreach ( $paramNodes as $paramNode )
        {
            $paramName = $paramNode->getAttribute("name");
            $paramValue = $xpath->GetText("",  $paramNode);

            $page->params[$paramName] = $paramValue;
        }

        return $page;
    }

    private function LoadRefererPageData( $page )
    {
        $refId = $page->ref;
        if (!isset($this->pages[$refId]))
        {
            trigger_error("Reference to unknown page with id = '$refId'", E_USER_WARNING);
        } else
        {
            $refPage = $this->pages[$refId];
            $page->Init($refPage);
        }
    }

    private function LoadPageTree()
    {
        $xml = @file_get_contents( PAGE_TREE_FILE );
        $doc = Util::CreateXmlDocument( $xml, TRUE );
        if ( $doc )
        {
            $xpath = new XPathHelper($doc);
            $root = $xpath->GetNode("/tree/node[@id='Index']");
            $this->LoadPageTreeNode( $xpath, $root );
        }
    }

    private function LoadPageTreeNode( XPathHelper $xpath, DOMNode $node, $parentPageId = NULL )
    {
        $id = $node->getAttribute("id");
        $pageInfo = isset($this->pages[$id]) ? $this->pages[$id] : NULL;

        if ( empty($pageInfo) )
        {
            $pageInfo = new PageInfo();
            $pageInfo->id = $id;
            $this->pages[$id] = $pageInfo;
        }

        if ( !empty($pageInfo->parent) )
        {
            trigger_error("Duplicate page node with id = '$id'", E_USER_WARNING);
            return $id;
        }

        $this->ReadAttribute($pageInfo, $node, "topMenuExpand");

        $this->ReadAttribute($pageInfo, $node, "sitemap");
        $this->ReadAttribute($pageInfo, $node, "link");

        $pageInfo->parent = $parentPageId;

        $childs = $xpath->GetNodes("node", $node);
        foreach ( $childs as $child )
        {
            $pageInfo->children[] = $this->LoadPageTreeNode($xpath, $child, $id);
        }
        return $id;
    }

    /**
     *
     * @param PageInfo $pageInfo
     * @param DOMNode $node
     * @param string $attrName
     * @param string $realAttrName is an attribute name in PageInfo class. If it is not set then real attribute name is the same with $attrName parameter.
     */
    private function ReadAttribute( PageInfo $pageInfo, DOMNode $node, $attrName, $realAttrName = NULL )
    {
        if ( is_null( $realAttrName ) )
        {
            $realAttrName = $attrName;
        }

        $value = $node->getAttribute($attrName);
        if ( $value === 'true' || $value === 'false' )
        {
            $pageInfo->$realAttrName = ($value === 'true');
        }
    }

    private function LoadQuickLinks( $filePath = QUICK_LINKS_FILE )
    {
        $xml = @file_get_contents( $filePath );
        if ($xml)
        {
            $pagesQuickLinks = $this->ParseQuickLinks( $xml );
            foreach ( $pagesQuickLinks as $pageId => $quickLinks )
            {
                if ( isset( $this->pages[$pageId] ) )
                {
                    $this->pages[$pageId]->quickLinks = $quickLinks;
                }
            }
        }
    }

    private function ParseQuickLinks( $xml )
    {
        $pagesQuickLinks = array();

        $doc = Util::CreateXmlDocument( $xml, TRUE );
        if ( $doc )
        {
            $xpath = new XPathHelper($doc);
            $nodes = $xpath->GetNodes('./items');

            foreach ( $nodes as $node )
            {
                $pageId = $node->getAttribute('page_id');

                $pageQuickLinks = array();
                $itemNodes = $xpath->GetNodes('item', $node);
                foreach ( $itemNodes as  $itemNode )
                {
                    $quickLink = new QuickLinkInfo();
                    $quickLink->pageId = $itemNode->getAttribute('page_id');
                    $quickLink->name   = $itemNode->getAttribute('name');
                    $quickLink->anchor = $itemNode->getAttribute('anchor');
                    $quickLink->link   = ($itemNode->getAttribute('link') === 'false' ? FALSE : TRUE);
                    $quickLink->class  = $itemNode->getAttribute('class');
                    $quickLink->target = ($itemNode->getAttribute('target') === 'false' ? FALSE : TRUE);

                    $pageQuickLinks[] = $quickLink;
                }
                $pagesQuickLinks[$pageId] = $pageQuickLinks;
            }
        }
        return $pagesQuickLinks;
    }

    private function LoadLngQuickLinks()
    {
        $filePath = str_replace( '%LNG%', $this->siteLanguage, LNG_QUICK_LINKS_FILE_PATTERN );
        $this->LoadQuickLinks( $filePath );
    }
}

?>
